#include "Color/Color.h"
#include "Material.h"
#include "Primitives/Primitives.h"
#include "Scene/Scene.h"
#include "Camara/Camara.h"
#include "Vector/Vector.h"
#include <iostream>
#include <assert.h>
#include <SDL/SDL.h>
using namespace std;

unsigned int screen_w = 500;
unsigned int screen_h = 500;
unsigned int oversampling = 3;

void draw_pixel32( SDL_Surface* surface, int x, int y, Uint32 pixel ){
	//Convert the pixels to 32 bit
	Uint32* pixels = (Uint32*)surface->pixels;
	//Set the pixel
	pixels[ ( y * surface->w ) + x ] = pixel;
}

int draw_screen(SDL_Surface* screen, Scene& scene){
		/* Por cada punto (pixel) de la pantalla */

	for(int i=-(int)screen_h/2;i<(int)screen_h/2;i++){
		for(int j=-(int)screen_w/2;j<(int)screen_w/2;j++){

			unsigned int r = 0;
			unsigned int g = 0;
			unsigned int b = 0;

			for(int ii=0;ii<oversampling;ii++){
				for(int jj=0;jj<oversampling;jj++){

					// calcula el color del rayo.
					// el i es negativo porque en la pantalla el positivo esta arriba
					Color c = scene.pixel( (j*(int)oversampling)+jj , -(i*(int)oversampling)-ii );
					r += c.red();
					g += c.green();
					b += c.blue();

				}
			}

			unsigned int oo = oversampling*oversampling;
			r /= oo;
			g /= oo;
			b /= oo;

			// colorea el pixel correspondiente en pantalla
			draw_pixel32( screen, j+screen_w/2, i+screen_h/2, SDL_MapRGB(screen->format, r, g, b) );

		}

		// Update Screen
		if( SDL_Flip( screen ) == -1 ) return -1;

	}

	return 0;

}

void init_scene(Scene& scene){

	Camara camara(Vector(300,-1000,300),Vector(0,1,0),Vector(0,0,1),500);

	scene.set_camera(camara);
	scene.set_screen(screen_w*oversampling,screen_h*oversampling,1.0/oversampling,1.0/oversampling);

	scene.set_ambient_light(0);
	scene.set_background_color(Color(150,150,200));
	scene.set_recursion_limit(2);
	scene.set_max_ray_distance(10000);

	Material m1;
	m1.diffuse_reflection = 0.75;
	m1.specular_reflection = 0.75;
	m1.shininess = 10;
	m1.reflection = 0.5;
	m1.transparency = 0;
	m1.refraction = 0;
	m1.ior = 1;
	m1.color = BLUE;

	Material m2;
	m2.diffuse_reflection = 0.75;
	m2.specular_reflection = 0.5;
	m2.shininess = 3;
	m2.reflection = 0;
	m2.transparency = 0;
	m2.refraction = 0;
	m2.ior = 1;
	m2.color = RED;

	Material m3;
	m3.diffuse_reflection = 1;
	m3.specular_reflection = 1;
	m3.shininess = 10;
	m3.reflection = 0;
	m3.transparency = 0.75;
	m3.refraction = 0;
	m3.ior = 1.3;
	m3.color = WHITE;

	Material mirror;
	mirror.diffuse_reflection = 1;
	mirror.specular_reflection = 0.5;
	mirror.shininess = 5;
	mirror.reflection = 0;
	mirror.transparency = 0;
	mirror.refraction = 0;
	mirror.ior = 1;
	mirror.color = GREEN;

	PointLight l;
	l.position = Vector(200,-300,800);
	l.diffuseColor = WHITE;
	l.diffusePower = 1;
	l.specularColor = WHITE;
	l.specularPower = 1;

	PointLight l2;
	l2.position = Vector(0,0,0);
	l2.diffuseColor = WHITE;
	l2.diffusePower = 1;
	l2.specularColor = WHITE;
	l2.specularPower = 1;

	scene.add_light(l);
	//scene.add_light(l2);

	scene.add_primitive(new Sphere(Vector(500,500,300),300,m2));
	scene.add_primitive(new Sphere(Vector(200,400,600),100,m1));
	scene.add_primitive(new Sphere(Vector(200,0,400),150,m3));
	scene.add_primitive(new Plane(Vector(0,-0.1,1).normalize(),-2000,mirror));

}

int main(int argc, char* argv[]){

	Scene scene;
	init_scene(scene);

	/* inicio SDL */
	SDL_Surface* screen = NULL;
	if( SDL_Init( SDL_INIT_EVERYTHING ) == -1 ) return 1;

	screen = SDL_SetVideoMode( screen_w, screen_h, 32, SDL_SWSURFACE );
	if( !screen ) return 1;

	/* Dibujo la imagen */
	if( draw_screen(screen, scene) == -1) return 1;

	SDL_Event event;
	bool quit = false;
	while(!quit) while( SDL_PollEvent( &event ) ) {
		
		if( event.type == SDL_QUIT ) quit=true;

		if( event.type == SDL_KEYDOWN ) {

			switch( event.key.keysym.sym ) {
				case SDLK_UP:
					scene.move_camara(UP,100);
					if( draw_screen(screen, scene) == -1) return 1;
					break;
				case SDLK_DOWN:
					scene.move_camara(UP,-100);
					if( draw_screen(screen, scene) == -1) return 1;
					break;
				case SDLK_RIGHT:
					scene.move_camara(RIGHT,100);
					if( draw_screen(screen, scene) == -1) return 1;
					break;
				case SDLK_LEFT:
					scene.move_camara(RIGHT,-100);
					if( draw_screen(screen, scene) == -1) return 1;
					break;
			}

		}

	}

	/* Quit SDL */
	SDL_Quit(); 

	return 0;
}
